/*
 * SendMediaPort.cpp
 *
 *  Created on: 2017年4月14日
 *      Author: chuanjiang.zh
 */

#include "SendMediaPort.h"
#include "TFileUtil.h"
#include "Path.h"
#include "Utility.h"
#include "BasicMacro.h"
#include "TStringUtil.h"
#include "RtpConst.h"
#include "CLog.h"

static void MyRtpSinkProc(HANDLE handle, StreamPacket* pPacket, void* pContext)
{
	SendMediaPort* pthis = (SendMediaPort*)pContext;
	pthis->handlePacket(pPacket);
}

SendMediaPort::SendMediaPort() :
	m_originSdp(),
	m_connected(false),
	m_medium(),
	m_running(false),
	m_localPort()
{
	m_pcmSource.setSink(this);
}

SendMediaPort::~SendMediaPort()
{
}

void SendMediaPort::setOriginSdp(const std::string& sdp)
{
	m_originSdp = sdp;
}

std::string SendMediaPort::getLocalSdp()
{
	if (!m_connected)
	{
		m_localSdp = m_originSdp;
	}
	return m_localSdp;
}

int SendMediaPort::setPeerSdp(std::string& peerSdp)
{
	m_connected = true;

	m_peerSdp = peerSdp;

	m_localSdp = apply(m_localSdp, m_peerSdp);

	int rc = setup(m_localSdp, m_peerSdp);

	return rc;
}

std::string SendMediaPort::getPeerSdp(std::string& offerSdp)
{
	m_peerSdp = offerSdp;
	m_localSdp = apply(m_originSdp, offerSdp);
	int rc = setup(m_localSdp, offerSdp);
	if (rc != 0)
	{
		return std::string();
	}

	m_connected = true;

	return m_localSdp;
}

int SendMediaPort::start()
{
	m_rtpCaster.setProc(MyRtpSinkProc, this);
	m_rtpCaster.startRecord("RecvAudio.pcm");

	m_rtpCaster.setPayload(m_medium.payload);

	m_rtpCaster.open(m_localPort, m_medium.ip.c_str(), m_medium.port);
	

	m_pcmSource.open(m_pcmFile.c_str());

	m_running = true;

	return 0;
}

void SendMediaPort::stop()
{
	m_running = false;

	m_rtpCaster.stop();

	m_rtpCaster.stopRecord();

	m_pcmSource.close();
}

void SendMediaPort::setPath(const std::string& pcmfile)
{
	m_pcmFile = pcmfile;
}


std::string SendMediaPort::apply(const std::string& localSdp, const std::string& peerSdp)
{
	sdp::SessionDescription local;
	local.parse(localSdp);

	sdp::SessionDescription peer;
	peer.parse(peerSdp);

	sdp::SessionDescription sdp;
	sdp.version = local.version;
	sdp.origin = local.origin;
	sdp.name = local.name;
	sdp.info = local.info;
	sdp.uri = local.uri;
	sdp.email = local.email;
	sdp.phone = local.phone;
	sdp.connection = local.connection;
	sdp.bandwidth = local.bandwidth;
	sdp.time = local.time;
	sdp.repeatTime = local.repeatTime;
	sdp.timeZone = local.timeZone;
	sdp.key = local.key;
	sdp.attributes = local.attributes;

	for (size_t i = 0; i < local.getMediumCount(); ++i)
	{
		sdp::Medium& medium = local.getMedium(i);
		size_t idx = peer.findMedium(medium.name);
		if (idx == (size_t)-1)
		{
			continue;
		}

		sdp::Medium& peerMedium = peer.getMedium(idx);

		sdp::Medium newMedium(medium.name, medium.port, medium.proto);
		newMedium.attributes = medium.attributes;
		newMedium.connection = medium.connection;
		newMedium.bandwidth = medium.bandwidth;
		newMedium.control = medium.control;

		for (size_t j = 0; j < medium.codecs.size(); ++j)
		{
			sdp::Codec& codec = medium.codecs[j];
			idx = peerMedium.findCodec(codec.name);
			if (idx == (size_t)-1)
			{
				continue;
			}

			sdp::Codec newCodec(codec);
			newCodec.payload = peerMedium.codecs[idx].payload;
			newMedium.addCodec(newCodec);
		}

		sdp.addMedium(newMedium);
	}

	return sdp.toString();
}

int SendMediaPort::setup(const std::string& localSdp, const std::string& peerSdp)
{
	sdp::SessionDescription local;
	local.parse(localSdp);

	sdp::SessionDescription peer;
	peer.parse(peerSdp);

	setupMedium(local, peer, "audio", m_medium, m_localPort);

	//comn::FileUtil::dump(local.toString(), "local.sdp");

	return 0;
}

bool SendMediaPort::setupMedium(sdp::SessionDescription& local, sdp::SessionDescription& peer,
	const char* name, RtpMedium& rtpMedium, int& localPort)
{
	bool found = false;
	size_t localIdx = local.findMedium(name);
	size_t peerIdx = peer.findMedium(name);
	if ((localIdx != -1) && (peerIdx != -1))
	{
		sdp::Medium& localMedium = local.getMedium(localIdx);
		sdp::Medium& peerMedium = peer.getMedium(peerIdx);

		rtpMedium.ip = peer.getConnection(peerMedium).address;
		rtpMedium.port = peerMedium.port;
		localPort = localMedium.port;
		rtpMedium.mode = localMedium.getMode();


		if (!localMedium.codecs.empty())
		{
			sdp::Codec& localCodec = localMedium.codecs[0];
			rtpMedium.payload = localCodec.payload;

			found = true;
		}

	}
	return found;
}

void SendMediaPort::handlePacket(StreamPacket* pPacket)
{
	//
}

void SendMediaPort::onPcmData(uint8_t* data, size_t size, int64_t pts)
{
	m_rtpCaster.sendPacket(data, size, m_medium.payload, false, size);
}

void SendMediaPort::setPacketSize(int size)
{
	m_pcmSource.setPacketSize(size);
}